提高应用程序性能
这些主题描述提高 GBase 8s ODBC Driver应用程序的性能的方法。
在数据传输过程中进行错误检查
IFX_LOB_XFERSIZE 环境变量用于指定在检查是否发生错误之前,从客户端应用程序传输到数据库服务器的 CLOB 或 BLOB 中的千字节数。
每当传输指定的千字节数据时都会发生错误检查。如果发生错误,则不会发送剩余的数据,并报告错误。如果没有发生错误,则继续文件传输直到结束。
IFX_LOB_XFERSIZE 值的范围是 1 到 9223372036854775808 千字节。在客户端设置 IFX_LOB_XFERSIZE 环境变量。
有关 IFX_LOB_XFERSIZE 的更多信息,请参阅《GBase 8s SQL 指南:参考》。
在 ODBC 中启用分隔标识符
缺省情况下,分隔标识符在通过 ODBC 连接时被禁用。
有三种方式启用它们,按优先级递减的顺序如下所示:
DELIMIDENT 连接字符串关键字
如果使用连接字符串连接,可以将关键字 DELIMIDENT 设置为启用或禁用分隔标识符。如果关键字设置为 y则为连接启用分隔标识符。如果关键字设置为 n 则为连接禁用分隔标识符。如果关键字存在但是没有设置值,则对是否启用分隔标识符没有影响。
例如,该连接字符串使用数据源(DSN)mydsn连接,并为此连接启用分隔标识符。
"DSN=mydsn;DELIMIDENT=y;"
该连接字符串还使用 DSN mydsn连接,但是对是否使用分隔标识符没有影响。
"DSN=mydsn;DELIMIDENT=;"
在连接字符串中设置 DELIMIDENT 关键字会覆盖任何启用或禁用分隔标识符的连接属性或环境变量。
SQL_INFX_ATTR_DELIMIDENT 连接属性
可以在连接之前通过设置 SQL_INFX_ATTR_DELIMIDENT 连接属性来启用或禁用给出连接的分隔标识符。SQL_INFX_ATTR_DELIMIDENT 连接属性接受下表列出的值。
表 1. SQL_INFX_ATTR_DELIMIDENT 连接属性允许的值
值 | 影响 |
---|---|
SQL_TRUE | 为此连接启用分隔标识符。 |
SQL_FALSE | 为此连接禁用分隔标识符。 |
SQL_IFX_CLEAR | 清除之前的设置,以便该连接属性对是否使用分隔标识符没有影响。 |
例如,该调用导致在创建连接时启用分隔标识符:
SQLSetConnectAttr(hdbc, SQL_INFX_ATTR_DELIMIDENT, SQL_TRUE, SQL_IS_INTEGER);
如果该连接属性设置为 SQL_TRUE 或 SQL_FALSE,则该设置覆盖 DELIMIDENT 环境变量,但是不覆盖 DELIMIDENT 连接字符串关键字。
DELIMIDENT 环境变量
在一些 GBase 8s API 中,例如 ESQL/C,通过将 DELIMIDENT 环境变量设置为任何值来启用分隔标识符。但是,在 ODBC 中,通过将 DELIMIDENT 环境变量设置为 y 来启用分隔标识符,将它设置为 n 来禁用分隔标识符。
连接级别优化
建立到数据库的连接是一个花费时间的过程。理想情况下,应用程序在连接打开时执行尽可能多的任务。
该过程可以通过以下方式实现:
- 使用 Windows™ Driver Manager 时汇集连接
- 在同一个的连接句柄上使用多个语句句柄
此外,可以通过设置以下连接级别属性来优化应用程序性能:
- AutoCommit 优化
- 消息传输优化(OPTMSG)
- Open-Fetch-Close 优化(OPTOFC)
优化查询执行
当使用准备好的 SQL 查询时,您必须考虑几个方面。
当使用准备好的 SQL 查询时,请考虑以下几点:
- SQLExecDirect 是针对 SQL 语句的单个执行的优化。因此,它用于不重复执行的 SQL 查询。
- 在多次执行 SQL 查询的情况下,使用 SQLPrepare 和 SQLExecute提高性能。通常情况下,可以使用输入和输入参数执行此操作。
- 可以从 ODBC 应用程序调用 SPL 例程来执行某些 SQL 任务,并可以单独使用 SQL 扩展完成的任务。因为,SPL 是数据库的本地语言,SPL 例程在创建时被解析和优化,而不是在运行时,SPL 例程可以提高某些任务的性能。SPL 例程还可以减少客户端应用程序和数据库服务器之间的流量,并降低程序的复杂性。
- 当使用 GBase 8s ODBC Driver 执行具有返回值的存储过程时,在结果集上调用一个访存之前,过程返回的错误不会返回到应用程序。执行过程后,立即可以获得来自存储过程的没有返回值的错误信息。
插入多行
使用插入游标有效地将行插入到批量表中。
要创建插入游标,通过使用 SQLSetStmtOption 设置 SQL_ENABLE_INSERT_CURSOR 属性,然后调用 SQLParamOptions,使用行数作为参数。可以对 VARCHAR、LVARCHAR 和不透明数据类型创建插入游标。
当打开插入游标时,在内存中创建一个缓冲区保存行。缓冲区在程序生成数据时接收数据行;然后当缓冲区为空时,将它们发送到数据库服务器。该缓冲区减少程序和数据服务器之间的流量。从而,插入速度更快。
自动释放游标
当应用程序使用游标时,通常会向数据库服务器发送 FREE 语句,以在不再需要该游标之后释放分配给游标的内存。
该语句的执行调用应用程序和数据库服务器之间的消息请求。当启用 AUTOFREE 时,GBase 8s ODBC Driver 保存消息请求,因为它不需要执行 FREE 语句。当数据库服务器关闭插入游标时,它自动释放分配给它的内存。
启用 AUTOFREE 功能
有两种方法启用 ODBC 应用程序的 AUTOFREE 功能。
使用 SQLSetConnectAttr 设置 SQL_INFX_ATTR_AUTO_FREE 属性时,可以在 C2 和 C5 之间(包括两者)的任何连接状态中进行设置,而只有当语句处于 S1 (分配)状态时,才可以使用 SQLSetStmtAttr 设置 SQL_INFX_ATTR_AUTO_FREE 属性。可以通过使用 SQLGetConnectAttr 或 SQLSetStmtAttr 检索 SQL_INFX_ATTR_AUTO_FREE 属性的值。
可以是使用以下方法启用 ODBC 应用程序的 AUTOFREE 功能:
-
使用 SQLSetConnectAttr 设置 SQL_INFX_ATTR_AUTO_FREE 属性。
当您使用 SQLSetConnectAttr启用该属性时,该连接的所有的新的语句都会继承该值。更改该属性的唯一方法是设置每一条语句并将它重新设置为语句的属性。连接属性缺省为 DISABLED 。
-
使用 SQLSetStmtAttr 设置 SQL_INFX_ATTR_AUTO_FREE 属性。
AUTOFREE 功能
AUTOFREE 功能仅适用于使用 SQLExecDirect 执行的结果生成语句,因为它打开了由相应的 SQLCloseCursor 或 SQLFreeStmt 关闭和释放的游标。
当应用程序必须准备一次语句并执行多次时,AUTOFREE 功能不起作用。(例如,使用 SQLPrepare 准备然后多次调用 SQLExecute 执行它。) 当在 SQLExecute 之后使用 SQLCloseCursor 关闭游标时,它只关闭游标但不释放数据库服务器端的游标内存。但是如果您使用具有 SQL_CLOSE 或 SQL_DROP 的 SQLFreeStmt关闭游标时,它不仅关闭游标还释放此游标。在后一种情况下,会节省网络往返,但是应用程序不会执行该语句直到它重新表达它为止。
启用 AUTOFREE 后,当应用程序使用具有 SQL_DROP 的 SQLCloseCursor 或 SQLFreeStmt 关闭游标时,应用程序会看到网络性能的提升。
延迟执行 SQL PREPARE 语句
可以通过启用 deferred-PREPARE 功能来延迟 SQLPrepare 语句的执行。
此功能适用于应用程序执行一系列的 SQLPrepare 和 SQLExecute 语句的动态 SQL 语句。它通过在应用程序对该语句调用 SQLExecute 之前不向数据库服务器发送 SQLPrepare语句的方式来优化到数据库服务器的往返消息的数量。
当启用 deferred-PREPARE 后,应用程序执行以下行为:
- 执行 SQLPrepare 不会将语句置于准备好的状态。
- 在执行语句之前,SQLPrepare 语句中的语法错误是未知的,因为该 SQL 语句在执行之前不会发送到数据库服务器。如果打开 open-fetch-close 优化功能,则直到第一次访存之前错误不会返回到客户端,因为 open-fetch-close 优化了 OPEN/FETCH,所以在第一次访存时发送 OPEN。
- 如果应用程序在调用 SQLPrepare 之后,SQLExecute 之前调用 SQLColAttributes 、SQLDescribeCol、SQLNumResultCols 和 SQLNumParams,则始终返回 HY010(函数序列错误)。
- 如果源描述符句柄在 SQLPrepare 之后,但在应用程序执行 SQLExecute之前调用,则 SQLCopyDesc 返回 HY010。
- 如果描述符句柄是一个 IRD,并且应用程序在 SQLPrepare 之后 SQLExecute之前调用,则 SQLGetDescField 和 SQLGetDescRec 返回 HY010。
可以使用以下方式启用 ODBC 应用程序的 deferred-PREPARE 功能:
- 使用 SQLSetConnectAttr 设置 SQL_INFX_ATTR_DEFERRED_PREPARE 属性。
- 当使用 SQLSetConnectAttr启用该属性时,所有为此连接新分配的语句都会继承该属性值。更改该属性的唯一方法是设置每一条语句并将它重新设置为语句的属性。连接属性缺省为 DISABLED 。
- 使用 SQLSetStmtAttr 设置 SQL_INFX_ATTR_AUTO_FREE 属性。
当使用 SQLSetConnectAttr 进行设置 SQL_INFX_ATTR_DEFERRED_PREPARE 属性时,可以在 C2 和 C5 之间(包括两者)的任何连接状态中进行设置 SQL_INFX_ATTR_DEFERRED_PREPARE 属性。而只有当语句处于 S1 (分配)状态时,才能使用 SQLSetStmtAttr 设置此属性。可以通过使用 SQLGetConnectAttr 或 SQLSetStmtAttr 检索 SQL_INFX_ATTR_DEFERRED_PREPARE 属性的值。
设置简单大对象访存数组大小
为了减少涉及多行简单大对象数据的访存的网络开销,可以设置数组大小。
当驱动程序接收到多行访存请求时,请设置数组大小,它优化访存缓冲区大小和内在的访存数组大小,并消除每个简单大对象的数据库服务器的往返行程。
将数组大小设置为大于 1 ,也会使其它数据类型的数据的性能提升。因为如果需要,它会自动增加访存缓冲区的大小。(如果指定的行数可以放在当前访存缓冲区中,则设置它的效果不大)。
应用程序可以通过设置语句属性 SQL_ATTR_ROW_ARRAY_SIZE 或将 ARD 头字段 SQL_DESC_ARRAY_SIZE 设置为大于 1 的值,然后调用 SQLFetch 或 SQLFetchScroll来请求返回多行。(SQL_ATTR_ROW_ARRAY_SIZE 的缺省值为 1。)该驱动程序在检索多行访存请求时会识别它并优化访存缓冲区大小和内部访存数组大小的设置。这些设置都基于内部元组大小,用户行数组大小的设置以及访存数组大小的当前设置。
不能在以下情景中使用内部访存数组功能:
-
当启用了 OPTOFC 和 deferred-PREPARE 时
要使用访存数组功能,驱动程序需要知道从数据库服务器接收数据之后,将访存请求发送到数据库服务器之前,行将有多大。当这两个功能都被启用时,在执行访存之前是获得不了这个信息的。
-
当使用滚动游标时
内部用于滚动游标的客户端到服务器的协议与用于访存数组的那些协议不同。数据库服务器在滚动游标中不支持简单大对象类,会返回一个错误。
-
当使用 SQLGetData 时
为了驱动程序使用访存数组功能,它必须能够告知数据库服务器准备在访存请求时准备接收多少数据。在 SQLFetch 之后调用 SQLGetData。
根据 ODBC 标准,当使用 block 游标时,应用程序必须在调用 SQLGetData 之前调用 SQLSetPos定位特定行上的游标。SQLSetPos只能用于滚动游标,并且不能在滚动游标中使用简单大对象列。同样根据标准,SQLGetData 不能与行集大小小于 1 的只进游标一起使用。
使用 SQLGetData 的替代方法是使用 SQLBindCol,它在调用 SQLFetch 之前出现。
您可能想要优化 SQL_ATTR_ROW_ARRAY_SIZE 的使用,以便应用程序根据传输到单个缓冲区中的最大行数设置该值。在准备好语句之后,应用程序可能调用 SQLGetStmtAttr 获取 SQL_INFX_ATTR_FET_ARR_SIZE 的值。如果数据符合一个访存缓冲区,则 SQL_INFX_ATTR_FET_ARR_SIZE 的内部设置等于 SQL_ATTR_ROW_ARRAY_SIZE 的应用程序的设置。在实践中,这只对大型结果集有用。
SPL 输出参数功能
GBase 8s ODBC Driver 支持 ODBC 定义的从数据库过程获取返回值的方法。
具体来说,ODBC 支持在过程调用转义序列中的等号前面的参数。与该参数关联的主机变量在执行语句时使用 SQLExecute 或 SQLExecDirect 更新。
在过程调用转义序列的 GBase 8s ODBC Driver 定义中,只返回一个值;因此,此功能具有以下限制:
-
使用此功能的过程必须只能返回一个值,尽管它们可能返回多行。
如果不符合条件,则会忽略参数及其绑定。
-
来自第一行的数据只能放在与绑定参数关联的主变量中,尽管用于此功能的过程可以返回多行。
要从 GBase 8s 数据库服务器返回多值,多行结果集,您必须像访存 select 语句的结果列那样访存数据。此输出参数功能可以与绑定列或列的现有应用程序一起使用,并在通过过程调用访问数据时调用 SQLFetch或调用 SQLFetch 和 SQLGetData 。因此,当返回多行时不会生成错误或警告。
可以使用其中一种或两种方法从存储过程检索数据。主机变量可以绑定为参数或列,或两者。如果使用独立的缓冲区,则只有作为参数的主机变量在语句执行时被更新,并且只有作为列绑定的主机变量在访存时被更新,通过 SQLGetData 访问的未绑定的列不受影响。
OUT 和 INOUT 参数
GBase 8s Client Software Development KitVersion 4.10 支持执行 SPL 期间使用 OUT 和 INOUT 参数。
支持以下数据类型:
- BIGINT
- BLOB
- BOOLEAN
- DATETIME
- CHAR
- CLOB
- DECIMAL
- FLOAT
- INT8
- INTEGER
- INTERVAL
- LVARCHAR
- MONEY
- NCHAR
- NVARCHAR
- SMALLFLOAT
- SMALLINT
- VARCHAR
在执行 SPL 时使用 OUT 或 INOUT 参数具有以下限制:
- 不支持集合数据类型。例如 LIST 、MULTISET 、ROW 和 SET。
- 不支持返回的结果集。执行具有 OUT 或 INOUT 参数的 SPL 之后,不能调用 SQLFetch 或 SQLGetData。
- 只能返回一个值,即每执行一个 SPL 只返回一个 OUT 或 INOUT 参数的集合。
下列 SPL 执行示例创建一个 OUT,一个 INOUT 和一个 IN(缺省)参数以及一个返回值。
create procedure myproc(OUT intparam INT, INOUT charparam char(20),
inparam int) returns int
<body of SPL>
end procedure;
下列代码示例 outinoutparamblob.c,显示如何使用具有 BLOB 、INTEGER 和 VARCHAR 数据类型的 OUT 和 INOUT 参数。
/* Drop procedure */
SQLExecDirect(hstmt, (UCHAR *)"drop procedure spl_out_param_blob;", SQL_NTS);
SQLExecDirect(hstmt, (UCHAR *)"drop table tab_blob;", SQL_NTS);
/* Create table with BLOB column */
rc = SQLExecDirect(hstmt, (UCHAR *)"create table tab_blob(c_blob BLOB,
c_int INTEGER, c_char varchar(20));", SQL_NTS);
if (checkError (rc, SQL_HANDLE_STMT, hstmt, (SQLCHAR *) "Error in Step 2 --
SQLExecDirect failed\n"))
goto Exit;
/* Insert one row into the table */
rc = SQLExecDirect(hstmt, (UCHAR *)"insert into tab_blob
values(filetoblob('insert.data', 'c'), 10, 'blob_test');", SQL_NTS);
if (checkError (rc, SQL_HANDLE_STMT, hstmt, (SQLCHAR *) "Error in Step 2
-- SQLExecDirect failed\n"))
goto Exit;
/* Create procedure */
rc = SQLExecDirect(hstmt, "CREATE PROCEDURE spl_out_param_blob(inParam int,
OUT blobparam BLOB, OUT intparam int, OUT charparam varchar(20)) \n"
"returning integer; \n"
"select c_blob, c_int, c_char into blobparam,
intparam, charparam from tab_blob; \n"
"return inParam; \n"
"end procedure; ",
SQL_NTS);
if (checkError (rc, SQL_HANDLE_STMT, hstmt, (SQLCHAR *) "Error in Step 2
-- SQLExecDirect failed\n"))
goto Exit;
/* Prepare stored procedure to be executed */
rc = SQLPrepare(hstmt, (UCHAR *)"{? = call spl_out_param_blob
(?, ?, ?, ?)}", SQL_NTS);
if (checkError (rc, SQL_HANDLE_STMT, hstmt, (SQLCHAR *)
"Error in Step 2 -- SQLPrepare failed\n"))
goto Exit;
/* Bind the required parameters */
rc = SQLBindParameter(hstmt, 1, SQL_PARAM_OUTPUT, SQL_C_LONG,
SQL_INTEGER, 3, 0, &sParm1, 0, &cbParm1);
if (checkError (rc, SQL_HANDLE_STMT, hstmt, (SQLCHAR *)
"Error in Step 2 -- SQLBindParameter 1 failed\n"))
goto Exit;
rc = SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_LONG,
SQL_INTEGER, 10, 0, &sParm2, 0, &cbParm2);
if (checkError (rc, SQL_HANDLE_STMT, hstmt, (SQLCHAR *)
"Error in Step 2 -- SQLBindParameter 2 failed\n"))
goto Exit;
rc = SQLBindParameter(hstmt, 3, SQL_PARAM_OUTPUT, SQL_C_BINARY,
SQL_LONGVARBINARY, sizeof(blob_buffer), 0, blob_buffer,
sizeof(blob_buffer), &cbParm3);
if (checkError (rc, SQL_HANDLE_STMT, hstmt, (SQLCHAR *)
"Error in Step 2 -- SQLBindParameter 3 failed\n"))
goto Exit;
rc = SQLBindParameter(hstmt, 4, SQL_PARAM_OUTPUT, SQL_C_LONG,
SQL_INTEGER, 10, 0, &sParm3, 0, &cbParm4);
if (checkError (rc, SQL_HANDLE_STMT, hstmt, (SQLCHAR *)
"Error in Step 2 -- SQLBindParameter 4 failed\n"))
goto Exit;
rc = SQLBindParameter (hstmt, 5, SQL_PARAM_OUTPUT, SQL_C_CHAR,
SQL_VARCHAR, sizeof(schar), 0, schar, sizeof(schar), &cbParm6);
if (checkError (rc, SQL_HANDLE_STMT, hstmt, (SQLCHAR *)
"Error in Step 2 -- SQLBindParameter 5 failed\n"))
goto Exit;
/* Exeute the prepared stored procedure */
rc = SQLExecute(hstmt);
if (checkError (rc, SQL_HANDLE_STMT, hstmt, (SQLCHAR *)
"Error in Step 2 -- SQLExecute failed\n"))
goto Exit;
len =
strlen("123456789abcdefghijklmnopqrstuvwxyz
1234567890123456789012345678901234567890 ");
if( (sParm2 != sParm1) || (10 != sParm3) ||
(strcmp("blob_test", schar)) || (cbParm3 != len) )
{
fprintf(stdout, "\n 1st Data compare failed!");
goto Exit;
}
else
{
fprintf(stdout, "\n 1st Data compare successful");
}
/* Reset the parameters */
rc = SQLFreeStmt(hstmt, SQL_RESET_PARAMS);
if (checkError (rc, SQL_HANDLE_STMT, hstmt, (SQLCHAR *)
"Error in Step 3 -- SQLFreeStmt failed\n"))
goto Exit;
/* Reset variables */
sParm1 = 0;
cbParm6 = cbParm1 = SQL_NTS;
cbParm3 = SQL_NULL_DATA;
schar[0]=0;
blob_buffer[0]=0;
异步执行
设计应用程序利用支持异步执行的数据源。异步调用不会加快执行速度,但是设计良好的应用程序运行效率更高。
开启异步执行本身不会提高性能。但是,设计良好的应用程序可以利用异步查询执行,允许用户在数据库服务器上对查询进行评估时处理其它事情。也许用户启动一个或多个子查询或者选择在其它应用程序中工作,而所有这些查询都在数据库服务器上执行。设计用于异步执行的应用程序,允许用户同时处理多个任务,从而使应用程序看起来运行得更快。
缺省情况下,应用程序调用 ODBC 驱动程序,然后以同步方式对数据库服务器执行语句。在这种操作模式下,驱动程序不会返回控制应用程序直到它自己的到数据库服务器的请求完成。对于需要几秒钟才能完成的语句,此控制返回延迟可能会导致性能下将。
一些数据源支持异步执行。当处于异步模式,应用程序调用 ODBC 驱动程序,控制会立刻返回。在此模式中,驱动程序将状态 SQL_STILL_EXECUTING 返回到应用程序,然后将适当的请求发送到数据库服务器执行。应用程序以不同的时间间隔轮询驱动程序,驱动程序在该时间点轮询数据库服务器以查看查询是否已经执行完成。如果查询仍在执行,则状态 SQL_STILL_EXECUTING 返回到应用程序。如果已经完成,则返回类似 SQL_SUCCESS 的状态,然后应用程序可以开始访存记录。
使用定位更新和删除更新数据
虽然定位更新不适用于所有类型的应用程序,但尽可能使用定位更新和删除。
定位更新(使用 UPDATE WHERE CURRENT OF CURSOR)允许您通过将数据库游标定位到要更改的行来更新数据,并通知驱动程序更改数据。您不必强制构建复杂的 SQL 语句;提供要更改的语句。
除了要使代码更易于维护,定位更新通常会提高性能。由于数据库服务器已经在行上定位(对于当前正在处理 SELECT 语句),因此定位要更改的行的多余查询是不必要的。如果该行必须定位,则数据库服务器通常具有指向可用行的内部指针(例如 ROWID)。
要支持使用滚动游标定位的 UPDATE 和 DELETE 语句,GBase 8s ODBC Driver 从原始的定位语句构造一个新的搜索的 UPDATE 或 DELETE 语句。但是,数据库服务器不能直接更新滚动游标。相反,GBase 8s ODBC Driver 会构造一个 WHERE 子句,用于引用在 WHERE CURRENT OF CURSOR 子句中引用的 SELECT 语句中访存的每个列。SELECT 语句的行集数据缓存中的值绑定到已经建立的 WHERE 子句中的每个值。
该定位方法比使用具有 FORWARD ONLY 游标的子句 WHERE CURRENT OF CURSOR 子句更慢,更容易出错。如果访存的行不包含唯一键值,则构建的 WHERE 子句可能标识一行或多行,这会导致许多行被删除和更新。以这种方式删除行会影响定位的 UPDATE 和 DELETE 语句,和使用滚动游标的 SQLSetPos 语句。
使用 SQLSpecialColumns 确定在 WHERE 子句中用于更新数据的最佳列集。很多时候,伪列提供了对数据的最快访问;您只能通过使用 SQLSpecialColumns 确定这些列。
许多应用程序不能设计为利用定位的更新和删除。这些应用程序通常通过形成 WHERE 子句来更新数据。该 WHERE 子句由结果集中返回的一部分列值组成。某些应用程序可能会使用所有可搜索的结果列或通过调用 SQLStatistics 来查找可能属于唯一索引的列的 WHERE 子句。这些方法通常有效,但是会导致相当复杂的查询。
考虑以下示例:
rc = SQLExecDirect (hstmt, "SELECT first_name, last_name, ssn,
address, city, state, zip FROM emp", SQL_NTS);
// fetchdata
⋮
rc = SQLExecDirect (hstmt, "UPDATE EMP SET ADDRESS = ?
WHERE first_name = ? AND last_name = ? AND ssn = ? AND
address = ? AND city = ? AND state = ? AND zip = ?", SQL_NTS);
// fairly complex query
应用程序应该调用 SQLSpecialColumns/SQL_BEST_ROWID 检索标识任何给定记录的最佳列集(可能是伪列)。许多数据库支持在表定义中没有显式用户定义的特定列,但是是每个表的隐藏列(例如,ROWID 、TID 和其它列)。这些伪列总是提供对数据的最快访问。因为它们通常指向记录的确切位置。因为伪列不是显式表定义的一部分,所以它们不会从 SQLSpecialColumns 返回。确定伪列是否存在的唯一方法是调用 SQLSpecialColumns。
考虑之前的示例,这次使用 SQLSpecialColumns:
⋮
rc = SQLSpecialColumns (hstmt, ..... 'emp', ...);
⋮
rc = SQLExecDirect (hstmt, "SELECT first_name, last_name, ssn,
address, city, state, zip, ROWID FROM emp", SQL_NTS);
// fetch data and probably "hide" ROWID from the user
⋮
rc = SQLExecDirect (hstmt, "UPDATE emp SET address = ? WHERE
ROWID = ?", SQL_NTS);
// fastest access to the data!
如果您的数据源不包含特定的伪列,则 SQLSpecialColumns的结果集由指定表上的最佳唯一索引组成(如果唯一索引存在)。因此,您的应用程序不会另外调用 SQLStatistics 来查找最小的唯一索引。
BIGINT 和 BIGSERIAL 数据类型
BIGINT 和 BIGSERIAL 数据类型具有与 INT8 和 SERIAL8 数据类型相同的范围。
但是,BIGINT 和 BIGSERIAL 在 INT8 和 SERIAL8 上的存储和计算有优势。
消息传输优化
如果激活消息传输优化功能(OPTMSG),则驱动程序可以最大限度地减少大多数 GBase 8s ODBC 函数的数据库服务器的消息传输。
另外,该驱动程序将来自数据库服务器的消息链接在一起,消除一些小消息包以实现优化消息传输。
要激活消息传输优化,将 SQL_INFX_ATTR_OPTMSG 语句属性设置为 1。优化的缺省值为:OFF。
消息链接限制
即使启用消息传输优化,GBase 8s ODBC 也不会链接 SQL 函数。
ODBC 不链接的 SQL 函数有:
- SQLDisconnect
- SQLConnect
- SQLEndTran
- SQLExecute(如果驱动程序使用 select 或调用过程返回结果,并且驱动程序使用 insert 游标指向批量插入)
- SQLExtendedFetch
- SQLFetch
- SQLFetchScroll
- SQLPrepare
当驱动程序接触到上表所列的函数时,它执行以下操作:
-
只有当遇到需要数据库服务器响应的 SQL 语句时,会将消息队列刷新到数据库服务器。
当驱动程序运行不需要网络流量的函数时,它不会刷新消息队列,例如 SQLAllocStmt。
-
继续后续 SQL 语句的消息链接。
禁用消息链接
可以选择禁用消息链接。
在禁用消息链接之前,请考虑以下情况:
- 一些 SQL 语句需要立即回复。如果禁用消息链接,请在限制的 SQL 语句完成后重新启动 OPTMSG 功能。
- 如果执行调试。可以在试图确定每个 SQL 语句应答时禁用 OPTMSG 功能。
- 如果启用 OPTMSG,该消息会在数据库服务器中列队,但是不会发送进行处理。考虑在程序中的最后一条 SQL 语句之前禁用消息链接,以确保数据库服务器在应用程序退出之前处理所有消息。
- 如果禁用消息链接,必须在需要它的 SQL 语句之后立即重置 SQL_INFX_ATTR_OPTMSG 属性,来避免意外链接。
以下示例显示如何禁用消息链接,通过在 DELETE 语句之后放置 SQL_INFX_ATTR_OPTMSG 属性。如果将该属性放在删除语句后,则驱动程序可以在下一条 SQL 语句之前时,刷新所有排队的消息:
SQLSetStmtOption(hstmt, SQL_INFX_ATTR_OPTMSG, 1);
SQLExecDirect(hstmt, (unsigned char *)
"delete from customer", SQL_NTS);
SQLSetStmtOption(hstmt, SQL_INFX_ATTR_OPTMSG, 0);
SQLExecDirect(hstmt, (unsigned char *)
"create index ix1 on customer (zipcode)", SQL_NTS);
意外消息链接会使其很难确定哪一个链接的语句失败。
在 CREATE INDEX 语句中,驱动程序将 DELETE 和 CREATE INDEX 语句发送到数据库服务器。
优化消息传输的错误
当启用 OPTMSG 功能时,GBase 8s ODBC 不会对任何连接的语句执行错误处理。
如果您不确定某个特定语句是否会产生错误,则在代码中包含错误处理语句,并不要为此语句启用消息链接。
当链接语句中发生错误后,数据库服务器停止后续语句的执行。例如,在以下代码片段中,它试图链接五条 INSERT 语句:
SQLExecDirect(hstmt, "create table tab1 (col1 INTEGER)", SQL_NTS);
/* enable message chaining */
SQLSetStmtOption(hstmt, SQL_INFX_ATTR_OPTMSG, 1);
/* these two INSERT statements execute successfully */
SQLExecDirect(hstmt, "insert into tab1 values (1)", SQL_NTS);
SQLExecDirect(hstmt, "insert into tab1 values (2)", SQL_NTS);
/* this INSERT statement generates an error because the data
* in the VALUES clause is not compatible with the column type */
SQLExecDirect(hstmt, "insert into tab1 values ('a')", SQL_NTS);
/* these two INSERT statements never execute */
SQLExecDirect(hstmt, "insert into tab1 values (3)", SQL_NTS);
SQLExecDirect(hstmt, "insert into tab1 values (4)", SQL_NTS);
/* disable message chaining */
SQLSetStmtOption(hstmt, SQL_INFX_ATTR_OPTMSG, 0);
/* commit work */
rc = SQLEndTran (SQL_HANDLE_DBC, hdbc, SQL_COMMIT);
if (rc != SQL_SUCCESS)
在此示例中,会发生以下操作:
- 驱动程序将这五个 INSERT 语句和 COMMIT WORK 语句发送到数据库服务器执行。
- 数据库将 1 和 2 的 col1 值插入到 tab1 表中。
- 第三条 INSERT 语句产生错误,因此数据服务器不会执行后续的 INSERT 语句或 COMMIT WORK 语句。
- 当队列到达 SQLEndTran 函数,驱动程序刷新消息队列。
- SQLEndTran 函数,它是链接语句中的最后一条语句,返回失败的 INSERT 语句的错误。
如果需要保存数据库服务器插入到 col1 的值,必须自己提交它们。